package com.it135.citytraffic.utils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.it135.citytraffic.pojo.entity.RoadCache;
import com.it135.citytraffic.pojo.entity.RoadStatistic;
import com.it135.citytraffic.pojo.entity.RoadTimeStatistic;
import com.it135.citytraffic.pojo.entity.UserRoadReason;
import com.it135.citytraffic.service.IRoadCacheService;
import com.it135.citytraffic.service.IRoadStatisticService;
import com.it135.citytraffic.service.IRoadTimeStatisticService;
import com.it135.citytraffic.service.IUserRoadReasonService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Component;


import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;


@Component
@Slf4j
@Data
public class RoadAnalyseUtils {

    private final IRoadStatisticService iRoadStatisticService;

    private final IRoadTimeStatisticService iRoadTimeStatisticService;

    private final IUserRoadReasonService iUserRoadReasonService;
    private final OpenAiChatModel openAiChatModel;

    private final IRoadCacheService iRoadCacheService;


    /**
     * @param name 要分析的路段的name
     * @param id   要分析的路段的路口id
     */

    public void timeAnalyse(long id, String name) {

        //1. 根据id获取messageBody

        StringBuilder stringBuilder = new StringBuilder();
        String roadDirection = "";//用俩判断上下两次路口的名字是否相同,相同的话加入同一个sb的信息中
        ArrayList<String> directionCache = new ArrayList<>();//路口不同方向的拥塞情况
        //1.1循环遍历相关路口的拥塞时间信息
        LambdaQueryWrapper<RoadStatistic> roadStatisticLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roadStatisticLambdaQueryWrapper.eq(RoadStatistic::getName, name);
        roadStatisticLambdaQueryWrapper.eq(RoadStatistic::getCrossingId, id);
        roadStatisticLambdaQueryWrapper.orderBy(true, true, RoadStatistic::getDirection);
        double statusAmount = 0.0;//用来计算平均拥塞度
        int num = 0;
        for (RoadStatistic roadStatistic : iRoadStatisticService.list(roadStatisticLambdaQueryWrapper)) {
            statusAmount += roadStatistic.getStatus();
            num += 1;
            String newRoadDirection = roadStatistic.getDirection();
            if (newRoadDirection.equals(roadDirection)) {//判断是不是同一个方向
                //是的话先不进行分析 继续添加数据
                stringBuilder.append("拥堵状况:")
                        .append(roadStatistic.getInfo()).append("时间分布:");
                LambdaQueryWrapper<RoadTimeStatistic> roadTimeStatisticLambdaQueryWrapper = new LambdaQueryWrapper<>();
                roadTimeStatisticLambdaQueryWrapper.eq(RoadTimeStatistic::getRoadStatisticId, roadStatistic.getId());
                for (RoadTimeStatistic roadTimeStatistic : iRoadTimeStatisticService.list(roadTimeStatisticLambdaQueryWrapper)) {
                    stringBuilder.append(roadTimeStatistic.getInfo())
                            .append(roadTimeStatistic.getCount()).append("次,");
                }
                //跟小滚road方向
                roadDirection = newRoadDirection;

            } else {
                //不是同一个方向 先对上一个方向的数据进行分析
                //先判断之前有没有数据
                if (!roadDirection.equals("")) {
                    SystemMessage systemDirectionMessage = new SystemMessage("某路段方向的时间拥塞数据," +
                            "试总结出拥塞相关规律(时间规律),不要其余繁杂信息,只要结论 不超过五十字(方向 拥塞情况以及时间规律),返回结果中的换行符(\\n)全部换成<br>");
                    UserMessage userMessage = new UserMessage(stringBuilder.toString());
                    String result = call(systemDirectionMessage, userMessage);
                    //处理数据  (收集数据)
                    directionCache.add(result);
                }
                //再添加下一个方向的数据
                //添加之前先清空stringBuilder
                stringBuilder.delete(0, stringBuilder.length());
                //添加当前循环的数据
                stringBuilder.append("方向:").append(roadStatistic.getDirection())
                        .append("拥堵状况:").append(roadStatistic.getInfo()).append("时间分布:");
                LambdaQueryWrapper<RoadTimeStatistic> roadTimeStatisticLambdaQueryWrapper = new LambdaQueryWrapper<>();
                roadTimeStatisticLambdaQueryWrapper.eq(RoadTimeStatistic::getRoadStatisticId, roadStatistic.getId());
                for (RoadTimeStatistic roadTimeStatistic : iRoadTimeStatisticService.list(roadTimeStatisticLambdaQueryWrapper)) {
                    stringBuilder.append(roadTimeStatistic.getInfo())
                            .append(roadTimeStatistic.getCount()).append("次,");
                    //更新road方向
                    roadDirection = newRoadDirection;
                }
            }
        }
        //循环结束后 string Builder中还有最后一个路段方向的数据 最后一次分析并加入cache
        String end = call(new SystemMessage("某路段方向的时间拥塞数据," +
                "试总结出拥塞相关规律(时间规律),不要其余繁杂信息,只要结论 不超过五十字(方向 " +
                "拥塞情况以及时间规律),返回结果中的换行符(\\n)全部换成<br>"), new UserMessage(stringBuilder.toString())
        );
        directionCache.add(end);
        //2分析路段数据并持久化
        //2.1对拿到的各个方向数据进行分析
//        log.info(directionCache.toString());
        SystemMessage systemRoadMessage = new SystemMessage("某路段各个方向的时间拥塞数据," +
                "试总结出拥塞相关规律(时间规律),不要其余繁杂信息,只要结论 不超过三百字(包含路段名,方向 拥塞情况以及时间规律),返回结果中的换行符(\\n)全部换成<br>");
        UserMessage userMessage = new UserMessage(directionCache.toString());
        String result = call(systemRoadMessage, userMessage);

        //2.3将分析结果存入数据库
        double statusAverageD = statusAmount / num;
        Double statusAverage= Math.round(statusAverageD * 1000.0) / 1000.0;//保留三位小数
        iRoadCacheService.saveOrUpdate(new RoadCache(name, id, result, LocalDateTime.now(), statusAverage, null, null));

    }

    public void reasonAnalyse(RoadCache roadCache) {

        LambdaQueryWrapper<UserRoadReason> userRoadReasonLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userRoadReasonLambdaQueryWrapper.eq(UserRoadReason::getRoadName, roadCache.getName());
        List<UserRoadReason> list = iUserRoadReasonService.list(userRoadReasonLambdaQueryWrapper);
        StringBuilder sb = new StringBuilder();
        SystemMessage systemMessage = new SystemMessage("我会给你" + roadCache.getName() + "发生拥堵的原因以及次数," +
                "请帮我总结结论,要简洁,不超过100个汉字,返回结果中的换行符(\\n)全部换成<br>");

        list.forEach(userRoadReason -> {
            String reason = ReasonsUtils.getReason(userRoadReason.getReason());
            sb.append("原因:").append(reason).append(",").append("次数:").append(userRoadReason.getCount());
        });
        UserMessage userMessage = new UserMessage(sb.toString());
        String result = call(systemMessage, userMessage);
        roadCache.setUpdateTime(LocalDateTime.now());
        roadCache.setReasonCache(result);
        iRoadCacheService.saveOrUpdate(roadCache);
    }
    public void roadSuggestion(RoadCache roadCache){
        SystemMessage systemMessage = new SystemMessage("我会告诉你路段的拥堵随时间关系描述,拥堵比(拥堵程度,0-5 数值越大拥堵程度越严重)以及拥堵原因分析," +
                "请帮我给出对交管部门的建议和可以施行的措施 直接分条举例,不要套话,不要总体建议 要简洁,不超过400个汉字,返回结果中的换行符(\\n)全部换成<br>");
        UserMessage userMessage = new UserMessage(roadCache.getAnalyseCache()+"平均拥堵比为:"+roadCache.getStatusAverage()+
                roadCache.getReasonCache());

        String result = call(systemMessage, userMessage);
        iRoadCacheService.saveOrUpdate(new RoadCache(roadCache.getName(), roadCache.getCrossingId()
                , roadCache.getAnalyseCache(), LocalDateTime.now(), roadCache.getStatusAverage(), roadCache.getReasonCache(), result));
    }

    private String call(SystemMessage systemMessage, UserMessage userMessage) {
        List<Message> allMessage = List.of(userMessage, systemMessage);
        OpenAiChatOptions openAiChatOptions = new OpenAiChatOptions();
        openAiChatOptions.setModel("gpt-3.5-turbo");
        Prompt prompt = new Prompt(allMessage, openAiChatOptions);
        ChatResponse analyse = openAiChatModel.call(prompt);
        return analyse.getResult().getOutput().getContent();
    }
}